﻿namespace Chameleon.Data
{
	using System;
	using System.ComponentModel.DataAnnotations;
	using System.Data;
	using System.Data.Entity;
	using System.Data.Entity.Validation;
	using System.Linq;

	/// <summary>
	/// Provides a persistence context for data-bound objects via Entity Framework.
	/// </summary>
	
	public abstract class EntityDepository : DbContext
	{
		#region IDepository

			/// <summary>
			/// Inserts an item into the underlying data context and returns a reference to the item.
			/// </summary>
			/// <typeparam name="TEntity">Type of the item to insert into the data context.</typeparam>
			/// <param name="item">Item to insert into the data context.</param>

			public virtual TEntity Insert<TEntity>( TEntity item ) where TEntity: class
			{
				Set<TEntity>().Add( item );
				return item;
			}


			/// <summary>
			/// Attaches a previously disconnected item to the context.
			/// </summary>
			/// <typeparam name="TEntity">Type of the item to attach to the context.</typeparam>
			/// <param name="item">Item to attach to the data context.</param>

			public virtual void Attach<TEntity>( TEntity item ) where TEntity: class
			{
				Set<TEntity>().Attach( item );
				Entry( item ).State = EntityState.Modified; // mark entity as modified
			}


			/// <summary>
			/// Deletes an item from the underlying data context.
			/// <para>This will not take effect until a commit is performed.</para>
			/// </summary>
			/// <typeparam name="TEntity">Type of the item to delete from the data context.</typeparam>
			/// <param name="item">Item to be deleted from the data context.</param>

			public virtual void Delete<TEntity>( TEntity item ) where TEntity: class
			{
				Set<TEntity>().Remove( item );
			}


			/// <summary>
			/// Submits any outstanding changes to the underlying data context.
			/// </summary>
			/// <exception cref="System.Data.Entity.Validation.DbEntityValidationException">
			/// Thrown if an object awaiting submission fails validation.
			/// </exception>

			public virtual void Submit()
			{
				SaveChanges();
			}

		#endregion


		#region IDisposable

			/// <summary>
			/// Performs tasks associated with freeing, releasing, or resetting unmanaged resources.
			/// </summary>
			/// <param name="disposing">When true, releases unmanaged resources being used by managed components.</param>
			
			protected override void Dispose( bool disposing ) 
			{
				base.Dispose( disposing );
			}

		#endregion


		#region Constructors

			/// <summary>
			/// Initializes a new instance by creating a new instance of a basic data context using the specified connection string.
			/// <para>
			/// This is useful for contexts where the entity mapping is explicitly defined through meta-data resources.
			/// </para>
			/// </summary>
			/// <param name="connection">Either the database name or a connection string. See remarks for specifics.</param>
			/// <remarks>
			/// From the DbContext remarks:
			/// The [connection] can also be passed in the form "name=myname", in which case the name must be found in the config file or an exception will be thrown.
			/// Note that the connection found in the app.config or web.config file can be a normal database connection string (not a special Entity Framework connection string) in which case the DbContext will use Code First.
			/// However, if the connection found in the config file is a special Entity Framework connection string, then the DbContext will use Database/Model First and the model specified in the connection string will be used.
			/// </remarks>
			
			protected EntityDepository( string connection ) : base( connection ) {}

		#endregion
	}
}
